#include "SwitchBuilder.h"

#include "ScriptCompiler/ScriptFileContext.h"

#include "ScriptCompiler/AST/ExpressionNode.h"
#include "ScriptCompiler/AST/SwitchNode.h"
#include "ScriptCompiler/AST/CaseNode.h"

#include "ScriptCompiler/ASTBuilder/ExpressionBuilder.h"
#include "ScriptCompiler/ASTBuilder/CaseBuilder.h"
#include "ScriptCompiler/ASTBuilder/SentenceBlockBuilder.h"


CSwitchBuilder::CSwitchBuilder(std::shared_ptr<CScriptFileContext> InContext)
{
    Context = InContext;
    Result = std::make_shared<CSwitchNode>(InContext);
}

bool CSwitchBuilder::ReadCurentToken()
{
    //skip switch
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::Switch)
        {
            Context->RaiseError(10120,Token,U"Expected 'switch'");
            return false;
        }
        Result ->Switch = Token;

        Context->CurrentTokenIndex++;
    }

    //skip '('
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::LeftParentheses)
        {
            Context->RaiseError(10121,Token,U"Expected '('");
            return false;
        }
        Context->CurrentTokenIndex++;
    }

    //find ')'
    uint64_t RightParenthesesIndex;
    {
        auto RightParenthesesPos=FindPairedParentheses(Context);
        if(!RightParenthesesPos)
        {
            //raise error, require ')'
            Context->RaiseError(10122,Context->GetCurrentToken(),U"Expected paired ')' ");
            return false;
        }
        RightParenthesesIndex=*RightParenthesesPos;
    }

    //read condition
    {
        auto ExpressionBuilder = std::make_shared<CExpressionBuilder>(Context,RightParenthesesIndex);
        if (!ExpressionBuilder->ReadCurentToken())
        {
            return false;
        }
        Result->Value = ExpressionBuilder->Result;
    }

    //skip ')'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::RightParentheses)
        {
            Context->RaiseError(10123,Token,U"Expected ')'");
            return false;
        }
        Context->CurrentTokenIndex++;
    }

    //skip '{'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::LeftBrace)
        {
            Context->RaiseError(10124,Token,U"Expected '{'");
            return false;
        }
        Context->CurrentTokenIndex++;
    }

    int32_t RightBraceIndex;
    {
        auto RightBracePos=FindPairedBrace(Context);
        if(!RightBracePos)
        {
            //raise error, require '}'
            Context->RaiseError(10125,Context->GetCurrentToken(), U"Expected paired '}' ");
            return false;
        }
        RightBraceIndex=*RightBracePos;
    }

    TVector<int32_t> CaseTokenIndexes;
    {
        int32_t CurrentIndex=Context->CurrentTokenIndex;
        while(CurrentIndex<RightBraceIndex)
        {
            auto Token=Context->GetToken(CurrentIndex);
            if(Token->Type==EScriptTokenType::Case
            || Token->Type==EScriptTokenType::Default
            )
            {
                CaseTokenIndexes.Add(CurrentIndex);
                CurrentIndex++;
                continue;
            }

            //skip {} block , incase there is a case in the block
            if(Token->Type==EScriptTokenType::LeftBrace)
            {
                auto RightBracePos=FindPairedBrace(CurrentIndex,Context);
                if(!RightBracePos)
                {
                    //raise error, require '}'
                    Context->RaiseError(10126,Context->GetCurrentToken(), U"Expected paired '}' ");
                    return false;
                }
                CurrentIndex=*RightBracePos+1;
                continue;
            }

            CurrentIndex++;
        }
    }

    //read cases
    {
        for(int32_t i=0;i<CaseTokenIndexes.Num();i++)
        {
            int32_t CaseTokenIndex=CaseTokenIndexes[i];
            int32_t NextCaseTokenIndex;
            if(i+1<CaseTokenIndexes.Num())
            {
                NextCaseTokenIndex=CaseTokenIndexes[i+1];
            }
            else
            {
                NextCaseTokenIndex=RightBraceIndex;
            }

            auto CaseBuilder=std::make_shared<CCaseBuilder>(Context,NextCaseTokenIndex);
            if(!CaseBuilder->ReadCurentToken())
            {
                return false;
            }
            Result->Cases.Add(CaseBuilder->Result);
        }

    }
    
    //skip '}'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::RightBrace)
        {
            Context->RaiseError(10127,Token,U"Expected '}'");
            return false;
        }
        Context->CurrentTokenIndex++;
    }

    return true;
    
    // {
    //     while (true)
    //     {
    //         auto Token = Context->GetCurrentToken();
    //         if (Token->Type == EScriptTokenType::RightBrace)
    //         {
    //             Context->CurrentTokenIndex++; //skip }
    //             return true;
    //         }
    //         else if (Token->Type == EScriptTokenType::Case)
    //         {
    //             auto CaseBuilder = std::make_shared<CCaseBuilder>(Context);
    //             if (!CaseBuilder->ReadCurentToken())
    //             {
    //                 return false;
    //             }
    //             Result->Cases.Add(CaseBuilder->Result);
    //         }   
    //         else if (Token->Type ==EScriptTokenType::Default)
    //         {   
    //             Context->CurrentTokenIndex++;  //skip default

    //             //check  and skip :
    //             {
    //                 auto ColonToken=Context->GetCurrentToken();
    //                 if(ColonToken->Type!=EScriptTokenType::Colon)
    //                 {
    //                     Context->RaiseError(10125,ColonToken,U"Expected ':' after default case ");
    //                     return false;
    //                 }

    //                  Context->CurrentTokenIndex++;  //skip colon
    //             }

    //             //read content
    //             {
    //                 auto SentenceBlockBuilder= std::make_shared<CSentenceBlockBuilder>(Context);
    //                 if(!SentenceBlockBuilder->ReadCurentToken())
    //                 {
    //                     return false;
    //                 }
    //                 Result->DefaultCase=SentenceBlockBuilder->Result;

    //                 auto Token= Context->GetCurrentToken();
    //                 if(Token->Type!=EScriptTokenType::RightBrace)
    //                 {
    //                     Context->RaiseError(10126,Token,U"exprected a '}' after default case ");
    //                     return false;
    //                 }

    //                 Context->CurrentTokenIndex++;  //skip }
    //                 return true;
                    
    //             }


    //         }
    //         else
    //         {
    //             Context->RaiseError(10127,Token,U"Expected 'case' or '}'");
    //             return false;
    //         }
    //     }
    // }

}
